﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Classes
{
    class GraphImpl : IGraphImpl
    {
        IList<City> cities;
        IList<Flight> flights;
        IList<City> citiesOfSpan;
        IList<Flight> flightsForSearch;
        IList<City>    sequenceOfParentCities;

        ListOfConnections listOfConnections;
        Connection connection;
      
        
        
        public GraphImpl()
        {
            citiesOfSpan = new List<City>();
            flights = new List<Flight>();
            cities = new List<City>();
            flightsForSearch = new List<Flight>();
            connection = new Connection();
            sequenceOfParentCities = new List<City>();

            listOfConnections = new ListOfConnections();
        }
        public IList<City> ReturnCityList()
        {
            return cities;
        }
        public bool IsEmpty()
        {
            return cities.Count == 0;
        }
      
        public ListOfConnections FindConnections(City from, City to)
        {
            IList<Flight> nonImportantFlights = new List<Flight>();
            from.Mark = true;
            ICollection<City> adj = GetAdjacencies(from);
            foreach(City c in adj)
            {
                if(c.Mark != true)
                {
                    connection.AddFlight(new Flight(from, c));
                    if(c != to)
                    {
                        FindConnections(c, to);
                    }
                    else
                    {
                        IList<Flight> pureFlights = PureConnection(to, connection.FlightList());
                        connection.SetFlightList(pureFlights);
                        listOfConnections.AddConnection(connection);

                    }
                }
            }
            return listOfConnections;

        }
        public IList<Flight> PureConnection(City to, IList<Flight> nonPurifiedConnection)
        {
           IList<City> theSequence =  GetSequenceOfParentCities(to);
           IList<Flight> purifiedConnection = new List<Flight>();
           theSequence.Add(to);
           foreach (Flight v in nonPurifiedConnection)
           {
               if (!theSequence.Contains(v.To))
               {
                   purifiedConnection.Remove(v);
               }
           }
           return purifiedConnection;
           
        }
        public IList<City> GetSequenceOfParentCities(City city)
        {
            foreach(City c in GetParentsOfThisCity(city))
            {
                sequenceOfParentCities.Add(c);
            }
            return sequenceOfParentCities;

        }
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    /*    public IList<Flight> SearchForConnection(City from, City to)
        {
            from.Mark = true;
            ICollection<City> adj = GetAdjacencies(from);
            foreach (City c in adj)
            {
                flightsForSearch.Add(new Flight(from, c));
                if (c != to)
                {
                    if (c.Mark != true)
                    {
                        SearchForConnection(c, to);
                    }
                }

            }
          
        }
        */
        public void AddCity(City c)
        {
            cities.Add(c);
        }
        public void AddFlight(City from, City to)
        {	//PRE (to,from) is not contained in the graph

            from.AddFlight(to);
        }

        public bool ContainsCity(City city)
        {
            return cities.Contains(city);
        }

        public bool IsAdjacent(City startCity, City endCity)
        {
            bool isAdjacent = false;
            foreach (Flight f in startCity.Flights())
            {
                if (f.To == endCity)
                {
                    isAdjacent = true;
                }
            }
            return isAdjacent;

        }
        
        public IList<City> GetAdjacencies(City city)
        {
            IList<City> list = new List<City>();
            foreach (Flight f in city.Flights())
            {
                list.Add(f.To);
            }
            return list;

        }


        /* I don't know how to implement this shit and when to use it
         public IEnumerator<City> Cities()
         {
             throw new System.NotImplementedException();
         }
         */

        public int GetNoOfCities()
        {
            int i = cities.Count;
            return i;
        }

        public int GetNoOfFlights()
        {
            int numberOfFlights = 0;
            foreach (City c in this.cities)
            {

                numberOfFlights += c.Flights().Count;
            }
            return numberOfFlights;
        }

        public void Clear()
        {
            cities = new List<City>();
        }

        /*      public void Bfs(City v)
              {
                  throw new System.NotImplementedException();

              }*/

        public void Dfs(City v)//normal version
        {
            v.Mark = true;
            Console.WriteLine(v.Name + " " + v.Country);
            ICollection<City> adj = GetAdjacencies(v);
            foreach (City u in adj)
            {
                if (u.Mark != true)
                {
                    Dfs(u);
                }
            }
        }
        public IList<City> SpanTreeCities(City city)
        {
            
            city.Mark = true;
            citiesOfSpan.Add(city);
            ICollection<City> adj = GetAdjacencies(city);
            foreach (City u in adj)
            {
                if (u.Mark != true)
                {
                    SpanTreeCities(u);
                }
            }
            return citiesOfSpan;

        }

      
        public IList<Flight> Connection(City from, City to)
        {
            IList<Flight> flightList = new List<Flight>();
            from.Mark = true;
            IList<City> adjencecies = GetAdjacencies(from);
            foreach(City u in adjencecies)
            {
                if (!
                    
                    u.Equals(to))
                {
                    if (u.Mark != true)
                    {
                        Flight flight = new Flight(from, u); 
                        flightList.Add(flight);
                        Console.WriteLine(flight.From.Name + " ---> " + flight.To.Name);
                        Console.ReadLine();
                        Connection(u, to);
                    }
                }
                
                else
                {
                    Flight flight = new Flight(from, u);
                    flightList.Add(flight);
                    Console.WriteLine(flight.From.Name + " ---> " + flight.To.Name);
                    break;
                }
                

            }
            
            return flightList;
        }

        public IList<Flight> GetSpanTree(City city)
        {
            IList<Flight> listOfFlights = new List<Flight>();
            city.Mark = true;
            ICollection<City> adj = GetAdjacencies(city);
            foreach (City u in adj)
            {
                if (u.Mark != true)
                {
                    Flight flight = new Flight(city, u);
                    listOfFlights.Add(flight);
                    Console.WriteLine(flight.From.Name + " ---> " + flight.To.Name);
                    GetSpanTree(u);
                }
            }
            
            return listOfFlights;

        }


        private bool ItIsTheLast(City c)
        {
            bool isLast = true;
            ICollection<City> adj = GetAdjacencies(c);
            foreach (City item in adj)
            {
                if (!item.Mark)
                {
                    isLast = false;
                }

            }


            return isLast;
        }


        public IList<City> GetCities(City city)
        {
            IList<City> listOfCities = new List<City>();
            city.Mark = true;
            ICollection<City> adj = GetAdjacencies(city);
            foreach (City u in adj)
            {
                if (u.Mark != true)
                {
                    listOfCities.Add(city);
                    GetCities(u);
                }
            }
            return listOfCities;
        }
        public IList<City> GetParentsOfThisCity(City city)
        {
            IList<City> listOfCities = new List<City>();
            foreach(City c in cities)
            {
                foreach (City i in GetAdjacencies(c))
                {
                    if (i == city)
                    {
                        listOfCities.Add(c);
                    }
                }
                    
            }
   
            return listOfCities;
        }



        public IList<City> GetCitiesConnection(City city)
        {
            IList<City> listOfCities = new List<City>();
            city.Mark = true;
            listOfCities.Add(city);
            Console.WriteLine(city.Name);
            Console.ReadLine();
            ICollection<City> adj = GetAdjacencies(city);
            foreach (City u in adj)
            {
                if (u.Mark != true)
                {
                    GetCitiesConnection(u);
                }
            }
            
            return listOfCities;
        }

        public bool DoesItHaveAnyChildrenThatAreOurSearchingCity(City theCityThatWeAreOn, City theCityThatWeAreGoingTo)
        {
            bool yes = false;
            if(theCityThatWeAreOn == theCityThatWeAreGoingTo)
            {
                yes = true;
            }
            return yes;
        }
        public IList<City> MakeASequenceOfCitiesFromASequenceOfCities(IList<City> cityList)//we add here a list of Cities from graph
        {
            IList<City> sequence = new List<City>();

            foreach (City c in cityList)
            {

                Console.WriteLine("The paretns of city " + c.Name + " are:");
                GetParentsOfThisCity(c);

                foreach (City f in GetParentsOfThisCity(c))
                {
                    Console.WriteLine(f.Name);

                    sequence.Add(f);
                }
                Console.ReadLine();

            }
            return sequence;
        }
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
          public IList<Flight> GetASpanTreesFlights(City cityFrom, City cityTo)
        {
            cityFrom.Mark = true;
            Boolean ok = false;
            ICollection<City> adj = GetAdjacencies(cityFrom);
            foreach (City u in adj)
            {
                if (!ok)
                {
                    if (u.Mark != true)
                    {
                        Flight flight = new Flight(cityFrom, u);
                        flights.Add(flight);

                        if (u != cityTo)
                        {
                            if (ItIsTheLast(u))
                            {
                                flights.RemoveAt(flights.Count - 1);
                                GetASpanTreesFlights(cityFrom, cityTo);
                            }
                            else
                            {
                                GetASpanTreesFlights(u, cityTo);
                            }
                        }
                        else
                        {
                            ok = true;
                        }
                    }
               }
            }
            return flights;
        }
        
        
        
        
        
        }





        /* Kawał dobrego kodu
         *         public IList<City> MakeASequenceOfCitiesFromASequenceOfCities(IList<City> cityList)//we add here a list of Cities from graph
        {
                            IList<City> sequence = new List<City>();

            foreach(City c in cityList)
            {

                Console.WriteLine("The paretns of city " + c.Name + " are:");
                GetParentsOfThisCity(c);

                foreach(City f in GetParentsOfThisCity(c))
                {
                    Console.WriteLine(f.Name);

                    sequence.Add(f);
                }
                Console.ReadLine();

            }
            return sequence;
        }


     /*   public IList<City> MakeASequenceOfCities(City city)
        {
            IList<City> sequence = new List<City>();
            IList<City> list = new List<City>();
            city.Mark = true;
            Console.WriteLine("Parents of " + city.Name + " city are :");
            list = GetParentsOfThisCity(city);
            foreach(City cityFromList in list)
            {
                if(cityFromList.Mark != true)
                {
                    Console.WriteLine(cityFromList);
                    sequence.Add(cityFromList);
                    MakeASequenceOfCities(cityFromList);
                }
                
            }

            Console.ReadLine();
            return sequence;

        }
        */


    }
        /*
        public IList<Flight> MakeARouteOnASpanTree(City from, City cityTo)
        {

            IList<Flight> listOfFlights = new List<Flight>();
            listOfFlights = GetSpanTree(from);
            IList<City> listOfInterestingCities = new List<City>();
            foreach(City c in GetParentsOfThisCity(from))
            {
                listOfInterestingCities.Add(c);
                MakeARouteOnASpanTree(c,)
            }
            foreach(Flight f in listOfFlights)
            {
                if()
            }
        }
         * */

    



        /***********************************************************************************************************************
        public IList<Flight> GetConnectionFromASpanTree(City from, City to)
        {
            bool yes = false;
            IList<Flight> listOfFlights = new List<Flight>();
            listOfFlights = GetSpanTree(from);
            foreach(Flight f in listOfFlights)
            {
                 yes = DoesItHaveAnyChildrenThatAreOurSearchingCity(from, f.To);
                if(yes != true)
                {
                    listOfFlights.Add(f);
                    GetConnectionFromASpanTree(f.To, to);
                }
                else
                {

                }



            }

        }
               

        }*/
      /*  public bool checkIfAnyOfThoseCitiesIsOurSearchingCity(City from, City to)
        {
            bool yes = false;
            if(from == to)
            {
                yes = true;
            }
            return yes;
        }
       */


       /* public void GetAConnection(City from, City to)
    {
        IList<Flight> flights = new List<Flight>();
            flights = GetSpanTree(from);
        foreach(Flight f in flights)
        {
            Console.WriteLine()
        }
    
    }*/



  

/*
 * 
 * 
 * 
 *  IList<Flight> flights = new List<Flight>();
     IList<City> adjencecies = GetAdjacencies(from);
     from.Mark = true;

     foreach(City city in adjencecies)
     {
         if (city != to && city.Mark != true)
         {
             Flight flight = new Flight(from, city);
             flights.Add(flight);
             Console.ReadLine();
             Connection(city, to);

         }
         else
         {
             Flight flight = new Flight(from, to);
             flights.Add(flight);
         }

     }
     foreach (Flight flight in flights)
     {
         Console.WriteLine(flight.From.Name + " " + flight.To.Name);
     }

public void Unmark()
 {
     throw new System.NotImplementedException();
 }
*/




